package com.pai4j.message.websocket;

import com.pai4j.message.core.sender.AbstractMessageSender;
import com.pai4j.message.model.MessageContext;
import com.pai4j.message.model.SendResult;
import com.pai4j.message.sender.MessageQueueSender;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import jakarta.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

/**
 * 组合消息发送器
 * 结合MQ持久化和WebSocket实时推送
 * 
 * 发送策略：
 * 1. 先通过MQ持久化消息（确保消息不丢失）
 * 2. 再通过WebSocket实时推送（用户在线时立即收到）
 *
 * @author PAI4J Team
 * @date 2025-11-01
 */
@Slf4j
@Component
public class CompositeMessageSender extends AbstractMessageSender {

    @Autowired(required = false)
    private MessageQueueSender mqSender;

    @Autowired(required = false)
    private WebSocketMessageSender wsSender;

    @Autowired(required = false)
    private WebSocketProperties webSocketProperties;

    @PostConstruct
    public void register() {
        com.pai4j.message.factory.MessageSenderFactory.register(this);
        log.info("CompositeMessageSender已注册");
    }

    @Override
    public String getChannel() {
        return "composite";
    }

    @Override
    protected SendResult doSend(MessageContext context) {
        if (!validateContext(context)) {
            return SendResult.failure("INVALID_CONTEXT", "消息上下文验证失败", getChannel());
        }

        List<SendResult> results = new ArrayList<>();
        SendResult mqResult = null;
        SendResult wsResult = null;

        // 1. 先通过MQ持久化（确保消息不丢失）
        if (mqSender != null && mqSender.isAvailable()) {
            try {
                mqResult = mqSender.send(context);
                results.add(mqResult);
                
                if (mqResult.isSuccess()) {
                   log.info("MQ持久化成功");
                } else {
                    log.warn("MQ持久化失败 => code:{}, message:{}", mqResult.getCode(), mqResult.getMessage());
                }
            } catch (Exception e) {
                log.error("MQ发送异常：{}", e.getMessage(), e);
                mqResult = SendResult.failure("MQ_ERROR", e.getMessage(), "message-queue");
                results.add(mqResult);
            }
        } else {
            log.warn("MessageQueueSender不可用，跳过MQ持久化");
        }

        // 2. 再通过WebSocket实时推送（尽力而为）
        if (wsSender != null && wsSender.isAvailable()) {
            try {
                wsResult = wsSender.send(context);
                results.add(wsResult);
                
                if (wsResult.isSuccess()) {
                    log.debug("WebSocket推送成功");
                } else {
                    log.debug("WebSocket推送失败（可能用户不在线） => code:{}", wsResult.getCode());
                }
            } catch (Exception e) {
                log.warn("WebSocket推送异常：{}", e.getMessage());
                wsResult = SendResult.failure("WS_ERROR", e.getMessage(), "websocket");
                results.add(wsResult);
            }
        } else {
            log.debug("WebSocketMessageSender不可用，跳过WebSocket推送");
        }

        // 3. 返回组合结果
        return combineResults(mqResult, wsResult);
    }

    /**
     * 组合多个发送结果
     *
     * @param mqResult MQ发送结果
     * @param wsResult WebSocket发送结果
     * @return 组合后的结果
     */
    private SendResult combineResults(SendResult mqResult, SendResult wsResult) {
        boolean mqSuccess = mqResult != null && mqResult.isSuccess();
        boolean wsSuccess = wsResult != null && wsResult.isSuccess();

        // 策略：MQ成功即为成功（WebSocket是可选的实时推送）
        if (mqSuccess) {
            SendResult result = SendResult.success( getChannel());
            result.addExtData("mqResult", mqResult);
            result.addExtData("wsResult", wsResult);
            result.addExtData("realtimePushed", wsSuccess);
            return result;
        }

        // MQ失败，检查WebSocket是否成功
        if (wsSuccess) {
            // WebSocket成功但MQ失败，返回部分成功
            SendResult result = SendResult.builder()
                    .success(true)
                    .code("PARTIAL_SUCCESS")
                    .message("实时推送成功，但持久化失败")
                    .channel(getChannel())
                    .build();
            result.addExtData("mqResult", mqResult);
            result.addExtData("wsResult", wsResult);
            result.addExtData("realtimePushed", true);
            result.addExtData("persisted", false);
            return result;
        }

        // 都失败
        SendResult result = SendResult.failure("SEND_FAILED", "MQ和WebSocket发送均失败", getChannel());
        result.addExtData("mqResult", mqResult);
        result.addExtData("wsResult", wsResult);
        return result;
    }

    @Override
    public boolean isAvailable() {
        // 只要MQ或WebSocket其中一个可用即可
        boolean mqAvailable = mqSender != null && mqSender.isAvailable();
        boolean wsAvailable = wsSender != null && wsSender.isAvailable();
        return mqAvailable || wsAvailable;
    }

    @Override
    public int getPriority() {
        return 9; // 优先级高，推荐使用
    }

    @Override
    protected boolean isRetryable(SendResult result) {
        // 如果是MQ失败导致的，可以重试
        if (result.getExtData() != null) {
            SendResult mqResult = (SendResult) result.getExtData().get("mqResult");
            if (mqResult != null && !mqResult.isSuccess()) {
                return "SEND_ERROR".equals(mqResult.getCode()) 
                        || "TIMEOUT".equals(mqResult.getCode())
                        || "NETWORK_ERROR".equals(mqResult.getCode());
            }
        }
        return false;
    }

    /**
     * 获取发送统计信息
     *
     * @return 统计信息
     */
    public String getSenderInfo() {
        return String.format("CompositeMessageSender[MQ:%s, WS:%s]",
                mqSender != null && mqSender.isAvailable() ? "Available" : "Unavailable",
                wsSender != null && wsSender.isAvailable() ? "Available" : "Unavailable");
    }
}

